#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
#include "Log.hpp"
#include "Comm.hpp"
#include "InetAddr.hpp"
#include "ThreadPool.hpp"
using namespace LogModule;
using namespace ThreadPoolModule;
const std::string default_ip = "127.0.0.1";
const int default_port = 8080;
using handler_t = std::function<std::string(const std::string&)>;
class Server
{
    
public:
    Server(handler_t handler,int port = default_port, std::string ip = default_ip)
        : _handler(handler),
          _port(port),
          _ip(ip)
    {
    }
    void InitServer()
    {
        // 创建套接字
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            LOG(LogLevel::ERROR) << "socket error";
            return;
        }
        // 填充网络信息
        memset(&_local, 0, sizeof(_local));
        _local.sin_family = AF_INET;
        _local.sin_port = htons(_port);
        // local.sin_addr这是一个结构体，结构体只能整体初始化，不能整体赋值
        _local.sin_addr.s_addr = inet_addr(_ip.c_str());
        // 任意绑定
        //_local.sin_addr.s_addr = INADDR_ANY;

        // 绑定
        int n = bind(_sockfd, CONV(&_local), sizeof(_local));
        if (n < 0)
        {
            LOG(LogLevel::ERROR) << "bind error";
            return;
        }
        // 设置为监听状态
        _listenfd = listen(_sockfd, 0);
        if (_listenfd < 0)
        {
            LOG(LogLevel::ERROR) << "listen error";
            return;
        }
    }
    // version_3 线程池版本

    void Start()
    {
        using task_t = std::function<void()>;
        _isrunning = true;
        ThreadPool<task_t>::GetInstance()->Start();
        while (_isrunning)
        {
            struct sockaddr_in peer;
            socklen_t peerlen = sizeof(peer);
            int sockfd = accept(_sockfd, CONV(&peer), &peerlen);
            InetAddr inetaddr(peer);
            if (sockfd < 0)
            {
                LOG(LogLevel::ERROR) << "accept error";
                return;
            }
            LOG(LogLevel::INFO) << "accept success,ip:" << inetaddr.Ip() << " port:" << inetaddr.Port() << " ,sockfd: " << sockfd;
            //task_t t = std::bind(&Server::HandlerRequest,this,sockfd);
            ThreadPool<task_t>::GetInstance()->Equeue([this,sockfd](){  this->HandlerRequest(sockfd);});
        }
        _isrunning = false;
        ThreadPool<task_t>::GetInstance()->Stop();

    }

    // //version_2 多线成版本 
    // struct Data
    // {
    //     int sockfd;
    //     pthread_t pthread_id;
    //     Server *server_ptr;
    // };
    // static void *ThreadFunction(void *arg)
    // {
    //     Data *d = (Data *)arg;
    //     //将线程设置为分离状态，它的回收由系统完成
    //     pthread_detach(d->pthread_id);
    //     d->server_ptr->HandlerRequest(d->sockfd);
    //     free(d);
    //     return nullptr;
    // }

    // void Start()
    // {
    //     _isrunning = true;
    //     while (_isrunning)
    //     {
    //         struct sockaddr_in peer;
    //         socklen_t peerlen = sizeof(peer);
    //         int sockfd = accept(_sockfd, CONV(&peer), &peerlen);
    //         InetAddr inetaddr(peer);
    //         if (sockfd < 0)
    //         {
    //             LOG(LogLevel::ERROR) << "accept error";
    //         }
    //         LOG(LogLevel::INFO) << "accept success,ip:" << inetaddr.Ip() << " port:" << inetaddr.Port() << " ,sockfd: " << sockfd;
    //         pthread_t thread;
    //         Data *d = new Data;
    //         d->sockfd = sockfd;
    //         d->server_ptr = this;
    //         d->pthread_id = thread;
    //         pthread_create(&thread, nullptr, ThreadFunction, (void *)d);
    //     }
    //     _isrunning = false;
    // }

    // version_1 多进程版本
    //  void Start()
    //  {
    //      _isrunning = true;
    //      while (_isrunning)
    //      {
    //          struct sockaddr_in peer;
    //          socklen_t peerlen = sizeof(peer);
    //          int sockfd = accept(_sockfd, CONV(&peer), &peerlen);
    //          InetAddr inetaddr(peer);
    //          if (sockfd < 0)
    //          {
    //              LOG(LogLevel::ERROR) << "accept error";
    //          }
    //          LOG(LogLevel::INFO) << "accept success,ip:" << inetaddr.Ip() << " port:" << inetaddr.Port() << " ,sockfd: " << sockfd;
    //          // version-1 多进程版本
    //          pid_t pid = fork();
    //          if (pid == 0)
    //          {
    //              //子进程关闭不需要的文件描述符
    //              close(_listenfd);
    //              if(fork()>0)
    //              {
    //                  //子进程
    //                  exit(0);
    //              }
    //              //孙子进程
    //              HandlerRequest(sockfd);
    //          }
    //          //关闭父进程的不需要的文件描述符，这里将accept的sockfd交给了子进程
    //          close(sockfd);
    //          //如果使用waitpid会阻塞，解决办法就是用孙子进程来完成这个任务，直接回收子进程，那么孙子进程就变成了孤儿进程，它的回收交给系统
    //          waitpid(pid,nullptr,0);
    //      }
    //      _isrunning = false;
    //  }
    void HandlerRequest(int sockfd)
    {
        char buffer[1024];
        while (true)
        {
            int n = read(sockfd, buffer, sizeof(buffer) - 1);
            // 读取成功
            if (n > 0)
            {
                buffer[n] = 0;
                LOG(LogLevel::INFO) << buffer;
                std::string message = _handler(buffer);
                //std::string message = "server echo# ";
                //message += buffer;
                write(sockfd, message.c_str(), message.size());
            }
            else if (n < 0) // 表示客户端关闭
            {

                LOG(LogLevel::INFO) << "client close";
                break;
            }
            else // 读取错误
            {
                LOG(LogLevel::ERROR) << "read error";
                break;
            }
        }
        // 文件描述符是有用的，有限的  -->使用完如果不关闭，也会导致资源泄露问题
        close(sockfd);
        return;
    }

private:
    int _sockfd;
    int _listenfd;
    bool _isrunning = false;
    int _port;
    std::string _ip;
    struct sockaddr_in _local;
    handler_t _handler;
};